import sys
import traceback
import json
import time
from datetime import datetime
from abc import ABCMeta, abstractmethod
from typing import Dict, Any, Optional


class GlobalExceptionHandler(metaclass=ABCMeta):
    """
    全局异常处理基类，项目中所有类应继承此类以实现统一异常处理

    功能:
    1. 捕获并标准化异常信息
    2. 通过Kafka发送异常数据
    3. 支持异常分类和严重程度标记
    4. 提供异常处理钩子函数，方便扩展
    """

    def __init__(self):
        # 初始化Kafka客户端
        self.kafka_producer = self._init_kafka_producer()
        # 异常计数器，用于流量控制
        self.exception_counter = 0
        # 最后一次发送异常的时间戳
        self.last_exception_time = 0

    def _init_kafka_producer(self) -> Any:
        """初始化Kafka生产者，子类可重写以实现特定配置"""
        try:
            from kafka import KafkaProducer

            return KafkaProducer(
                bootstrap_servers=["kafka-broker:9092"],  # 替换为实际的Kafka地址
                value_serializer=lambda v: json.dumps(v).encode("utf-8"),
                retries=3,
                linger_ms=5,  # 批量发送优化
            )
        except ImportError:
            print("Kafka模块未安装，异常将不会发送到Kafka")
            return None
        except Exception as e:
            print(f"Kafka连接初始化失败: {str(e)}")
            return None

    def _get_exception_severity(self, e: Exception) -> str:
        """
        确定异常的严重程度

        Args:
            e: 异常实例

        Returns:
            严重程度: critical, error, warning, info
        """
        # 可以根据异常类型定制严重程度
        critical_exceptions = (SystemExit, KeyboardInterrupt, MemoryError)
        error_exceptions = (ValueError, TypeError, IndexError, KeyError, IOError)

        if isinstance(e, critical_exceptions):
            return "critical"
        elif isinstance(e, error_exceptions):
            return "error"
        else:
            return "warning"

    def _format_exception_data(
        self, e: Exception, context: Optional[Dict[str, Any]] = None
    ) -> Dict[str, Any]:
        """
        格式化异常数据为统一结构

        Args:
            e: 异常实例
            context: 额外的上下文信息

        Returns:
            格式化后的异常数据字典
        """
        # 获取详细的堆栈跟踪信息
        exc_type, exc_value, exc_traceback = sys.exc_info()
        stack_trace = traceback.format_exception(exc_type, exc_value, exc_traceback)

        # 基础异常信息
        exception_data = {
            "timestamp": datetime.utcnow().isoformat() + "Z",  # UTC时间，便于跨时区处理
            "exception_type": e.__class__.__name__,
            "message": str(e),
            "severity": self._get_exception_severity(e),
            "stack_trace": "".join(stack_trace),
            "module": self.__class__.__module__,
            "class_name": self.__class__.__name__,
            "process_id": str(sys.getpid()),
            "context": context or {},
        }

        # 调用钩子函数，允许子类添加更多信息
        self._extend_exception_data(exception_data, e)

        return exception_data

    def _extend_exception_data(self, data: Dict[str, Any], e: Exception) -> None:
        """
        钩子函数，用于扩展异常数据，子类可重写

        Args:
            data: 已格式化的异常数据字典
            e: 异常实例
        """
        pass  # 子类实现

    def _send_to_kafka(self, data: Dict[str, Any]) -> bool:
        """
        将异常数据发送到Kafka

        Args:
            data: 格式化后的异常数据

        Returns:
            发送是否成功
        """
        if not self.kafka_producer:
            return False

        try:
            # 根据严重程度发送到不同的topic
            topic = f"system-exceptions-{data['severity']}"
            future = self.kafka_producer.send(topic, value=data)
            # 不阻塞，但等待结果以捕获异常
            future.add_callback(self._kafka_success_callback)
            future.add_errback(self._kafka_error_callback)
            return True
        except Exception as e:
            print(f"发送异常到Kafka失败: {str(e)}")
            return False

    def _kafka_success_callback(self, metadata) -> None:
        """Kafka发送成功的回调函数"""
        # 可以记录发送成功的metrics
        pass

    def _kafka_error_callback(self, exception) -> None:
        """Kafka发送失败的回调函数"""
        print(f"Kafka发送异常: {str(exception)}")

    def _log_to_local(self, data: Dict[str, Any]) -> None:
        """本地日志记录，作为Kafka发送失败的备份"""
        try:
            import logging

            logger = logging.getLogger(self.__class__.__name__)

            log_message = (
                f"[{data['timestamp']}] {data['severity'].upper()}: {data['exception_type']} - "
                f"{data['message']} in {data['class_name']}"
            )

            if data["severity"] == "critical":
                logger.critical(log_message, exc_info=True)
            elif data["severity"] == "error":
                logger.error(log_message, exc_info=True)
            else:
                logger.warning(log_message)
        except Exception as e:
            print(f"本地日志记录失败: {str(e)}")

    def handle_exception(
        self,
        e: Exception,
        context: Optional[Dict[str, Any]] = None,
        send_to_kafka: bool = True,
        log_local: bool = True,
    ) -> Dict[str, Any]:
        """
        处理异常的主方法

        Args:
            e: 异常实例
            context: 额外的上下文信息
            send_to_kafka: 是否发送到Kafka
            log_local: 是否记录到本地日志

        Returns:
            格式化后的异常数据
        """
        # 格式化异常数据
        exception_data = self._format_exception_data(e, context)

        # 记录到本地日志
        if log_local:
            self._log_to_local(exception_data)

        # 发送到Kafka
        if send_to_kafka:
            # 简单的流量控制，防止异常风暴
            current_time = time.time()
            if current_time - self.last_exception_time < 1:  # 1秒内最多发送10条
                self.exception_counter += 1
                if self.exception_counter > 10:
                    print("异常频率过高，暂时停止发送到Kafka")
                    send_to_kafka = False
            else:
                self.exception_counter = 0
                self.last_exception_time = current_time

            if send_to_kafka:
                self._send_to_kafka(exception_data)

        # 调用异常后处理钩子
        self._post_exception_handler(exception_data, e)

        return exception_data

    def _post_exception_handler(self, data: Dict[str, Any], e: Exception) -> None:
        """
        异常处理后的钩子函数，子类可重写以实现特定逻辑
        如：报警、自动修复等
        """
        pass

    def execute_safely(self, func, *args, **kwargs) -> Any:
        """
        安全执行函数的装饰器风格方法

        Args:
            func: 要执行的函数
            *args: 函数参数
            **kwargs: 函数关键字参数

        Returns:
            函数执行结果，若发生异常则返回None
        """
        try:
            return func(*args, **kwargs)
        except Exception as e:
            # 收集函数调用的上下文信息
            context = {
                "function": func.__name__,
                "args": str(args),
                "kwargs": str(kwargs),
            }
            self.handle_exception(e, context)
            return None
